#include "Notifier.h"

#include <QDebug>
#include <QNetworkConfigurationManager>
#include <QSettings>
#include <limits>

Notifier::Notifier(QObject *parent)
    : QObject(parent), m_networkSession(0), m_tcpSocket(0)
{
    qDebug() << "Notifier()";
    QNetworkConfigurationManager manager;
    if (manager.capabilities() & QNetworkConfigurationManager::NetworkSessionRequired) {
        QSettings settings("notifier.cfg", QSettings::IniFormat);
        const QString id = settings.value("Network/Configuration").toString();

        QNetworkConfiguration config = manager.configurationFromIdentifier(id);
        if ((config.state() & QNetworkConfiguration::Discovered) !=
                QNetworkConfiguration::Discovered) {
            config = manager.defaultConfiguration();
        }

        m_networkSession = new QNetworkSession(config, this);
        connect(m_networkSession, SIGNAL(opened()), this, SLOT(sessionOpened()));

        m_networkSession->open();
    } else {
        sessionOpened();
    }

    connect(&m_tcpServer, SIGNAL(newConnection()), this, SLOT(connected()));
}

void Notifier::sessionOpened()
{
    qDebug() << "sessionOpened()";

    QSettings settings("notifier.cfg", QSettings::IniFormat);

    // Save the used configuration
    if (m_networkSession) {
        qDebug() << "this";
        QNetworkConfiguration config = m_networkSession->configuration();
        QString id;
        if (config.type() == QNetworkConfiguration::UserChoice) {
            id = m_networkSession->sessionProperty("UserChoiceConfiguration").toString();
        } else {
            id = config.identifier();
        }
        settings.setValue("Network/Configuration", id);
    }

    QHostAddress hostAddress;
    const QString ipAddress = settings.value("Network/HostAddress").toString();
    bool portIsValid = false;
    qint16 port = settings.value("Network/Port").toUInt(&portIsValid);

    // if we did not find one, use IPv4 localhost
    if (ipAddress.isEmpty() || ipAddress.contains("Any", Qt::CaseInsensitive)) {
        hostAddress = QHostAddress(QHostAddress::Any);
        if (ipAddress.isEmpty()) {
            settings.setValue("Network/HostAddress", "Any");
        }
    } else if (ipAddress.contains("Auto", Qt::CaseInsensitive)) {
        QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
        // use the first non-localhost IPv4 address
        for (int i = 0; i < ipAddressesList.size(); ++i) {
            if (ipAddressesList.at(i) != QHostAddress::LocalHost
                    && ipAddressesList.at(i).toIPv4Address())
            {
                hostAddress = ipAddressesList.at(i);
                break;
            }
        }
    } else {
        hostAddress = QHostAddress(ipAddress);
    }

    if (port < 1024 && !portIsValid) {
        port = 3425;
        qDebug() << tr("Warning! Port smaller than 1024. Use default %1")
                    .arg(port);
        settings.setValue("Network/Port", port);
    }

    if (!m_tcpServer.listen(hostAddress, port)) {
        qDebug() << tr("Notifier")
                 << tr("Unable to start the server: %1.")
                    .arg(m_tcpServer.errorString());
        return;
    }

    qDebug() << tr("The server is running on\n\nIP: %1\nport: %2\n\n"
                   "Run the Notifier server now.")
                .arg(m_tcpServer.serverAddress().toString()).arg(m_tcpServer.serverPort());
}

void Notifier::connected()
{
    if (m_tcpServer.hasPendingConnections()) {
        m_tcpSocket = m_tcpServer.nextPendingConnection();
        QObject::connect(m_tcpSocket, SIGNAL(readyRead()), this, SLOT(readNotify()));
    }
}

void Notifier::readNotify()
{
    qDebug() << "readNotify";

    if (!m_tcpSocket) {
        qDebug() << "wrong client connection";
    }

    QDataStream in(m_tcpSocket);
    in.setVersion(QDataStream::Qt_4_0);
    QObject::connect(m_tcpSocket, SIGNAL(disconnected()), m_tcpSocket, SLOT(deleteLater()));

    quint16 m_blockSize = 0;
    if (m_blockSize == 0) {
        if (m_tcpSocket->bytesAvailable() < (int)sizeof(quint16)) {
            qDebug() << "Wrong block size";
            qDebug() << "clientConnection->bytesAvailable() : " << m_tcpSocket->bytesAvailable();
            qDebug() << "(int)sizeof(quint16) : " << (int)sizeof(quint16);
            return;
        }

        in >> m_blockSize;
    }

    if (m_tcpSocket->bytesAvailable() < m_blockSize) {
        qDebug() << "Readed block size not equal sended block";
        return;
    }

    Event event;
    in >> event;
    notify.addEvent(event);
}

